﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OnlineMealOrdering.Common
{
    public static class PolygonHelp
    {
        const double INFINITY = 1e10;
        const double ESP = 1e-5;
        const int MAX_N = 1000;

        public struct XPoint
        {
            public double x, y;

            public XPoint(double _x, double _y)
            {
                x = _x;
                y = _y;
            }
        };

        public struct LineSegment
        {
            public XPoint pt1, pt2;
        };

        /// 判断点在多边形内
        /// <summary>
        /// 如果点在多边形内： 返回0
        /// 如果点在多边形边上： 返回1
        /// 如果点在多边形外： 返回2
        /// </summary>
        /// <param name="polygon">多边形顶点</param>
        /// <param name="point">当前点</param>
        /// <returns></returns>
        public static int InPolygon(XPoint[] polygon, XPoint point)
        {
            int n = polygon.Length;
            int count = 0;
            LineSegment line;
            line.pt1 = point;
            line.pt2.y = point.y;
            line.pt2.x = -INFINITY;
            for (int i = 0; i < n; i++)
            {
                //得到多边形的一条边
                LineSegment side;
                side.pt1 = polygon[i];
                side.pt2 = polygon[(i + 1) % n];
                if (IsOnline(point, side))
                {
                    return 1;
                }
                // 如果side平行x轴则不作考虑
                if (Math.Abs(side.pt1.y - side.pt2.y) < ESP)
                {
                    continue;
                }
                if (IsOnline(side.pt1, line))
                {
                    if (side.pt1.y > side.pt2.y)
                        count++;
                }
                else if (IsOnline(side.pt2, line))
                {
                    if (side.pt2.y > side.pt1.y)
                        count++;
                }
                else if (Intersect(line, side))
                {
                    count++;
                }
            }
            if (count % 2 == 1)
            {
                return 0;
            }
            else
            {
                return 2;
            }
        }

        // 计算叉乘 |P0P1| × |P0P2|
        public static double Multiply(XPoint p1, XPoint p2, XPoint p0)
        {
            return ((p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y));
        }

        // 判断线段是否包含点point
        public static bool IsOnline(XPoint point, LineSegment line)
        {
            return ((Math.Abs(Multiply(line.pt1, line.pt2, point)) < ESP) &&
            ((point.x - line.pt1.x) * (point.x - line.pt2.x) <= 0) &&
            ((point.y - line.pt1.y) * (point.y - line.pt2.y) <= 0));
        }

        // 判断线段相交
        public static bool Intersect(LineSegment L1, LineSegment L2)
        {
            return ((Math.Max(L1.pt1.x, L1.pt2.x) >= Math.Min(L2.pt1.x, L2.pt2.x)) &&
            (Math.Max(L2.pt1.x, L2.pt2.x) >= Math.Min(L1.pt1.x, L1.pt2.x)) &&
            (Math.Max(L1.pt1.y, L1.pt2.y) >= Math.Min(L2.pt1.y, L2.pt2.y)) &&
            (Math.Max(L2.pt1.y, L2.pt2.y) >= Math.Min(L1.pt1.y, L1.pt2.y)) &&
            (Multiply(L2.pt1, L1.pt2, L1.pt1) * Multiply(L1.pt2, L2.pt2, L1.pt1) >= 0) &&
            (Multiply(L1.pt1, L2.pt2, L2.pt1) * Multiply(L2.pt2, L1.pt2, L2.pt1) >= 0));
        }

        /// 判断点在多边形内
        /// <summary>
        /// 如果点在多边形内： 返回0
        /// 如果点在多边形边上： 返回1
        /// 如果点在多边形外： 返回2
        /// </summary>
        /// <param name="polygon">定点集合，以30.192353,120.164766|30.192712,120.175851|30.189668,120.170192的方式存在</param>
        /// <param name="point">当前点</param>
        /// <returns></returns>
        public static int InPolygon(string _lat, string _lng, string _polygon)
        {
            XPoint mypoint = new XPoint();
            mypoint.x = Convert.ToDouble(_lat);
            mypoint.y = Convert.ToDouble(_lng);

            string Polygon = _polygon;

            string[] PolygonArray = Polygon.Split('|');
            PolygonHelp.XPoint[] curvePoints = new PolygonHelp.XPoint[PolygonArray.Length - 1];

            for (int i = 0; i < PolygonArray.Length - 1; i++)
            {
                string[] point_value = PolygonArray[i].Split(',');
                curvePoints[i] = new PolygonHelp.XPoint((Convert.ToDouble(point_value[0])), (Convert.ToDouble(point_value[1])));
            }

            int rs = InPolygon(curvePoints, mypoint);
            return rs;
        }
    }
}
